package com.iwhalecloud.bss.kite.cucc.service.pos.bcmc.handler.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iwhalecloud.bss.kite.client.dto.inst.InstAttrDTO;
import com.iwhalecloud.bss.kite.common.util.JsonUtils;
import com.iwhalecloud.bss.kite.common.util.KiteDateUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.api.attr.ILocalQueryScenePersonInfoService;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAccountDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosAttrDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsFeeDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosGoodsPayRealtionDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosProductDTO;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalKeyConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalPosConsts;
import com.iwhalecloud.bss.kite.cucc.common.util.DateUtils;
import com.iwhalecloud.bss.kite.cucc.service.pos.bcmc.BcmcPosContext;
import com.iwhalecloud.bss.kite.cucc.service.pos.handler.CuccPosServiceUtils;
import com.iwhalecloud.bss.kite.cucc.service.util.ChangeTypeUtils;
import com.iwhalecloud.bss.kite.cucc.spec.impl.transfer.GoodsInfoTransfer;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferCache;
import com.iwhalecloud.bss.kite.dataservice.cache.ProductCache;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Offer;
import com.iwhalecloud.bss.kite.dataservice.entity.spec.Product;
import com.iwhalecloud.bss.kite.dataservice.util.IdUtils;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.dto.KiteInstRelDTO;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.inst.KiteAttr;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInst;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstAcct;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstContract;
import com.iwhalecloud.bss.kite.manager.inst.KiteOfferInstDiscount;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInst;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosOfferInstVO;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosOfferObjInstRelVO;
import com.iwhalecloud.bss.kite.service.ord.pos.vo.KitePosProdInstVO;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.bss.common.util.StringUtil;
import com.ztesoft.bss.svcability.util.ListUtil;

/**
 * <Description> <br>
 * 组装商品信息节点
 *
 * @author XXZ<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2020年12月15日 <br>
 * @since R9.0<br>
 * @see com.iwhalecloud.bss.kite.cucc.service.pos.bcmc.handler.impl <br>
 */
@Service
public class BcmcPosGoodsHandler extends AbstractBcmcPosHandler {

    @Autowired
    private IQuerySceneInstService querySceneInstService;

    @Autowired
    private ILocalQueryScenePersonInfoService queryScenePersonService;

    @Resource
    private IOperateSceneInstService operateSceneInstService;

    @Override
    public void doHandle(BcmcPosContext context) {
        // 1.工单实例与极简实例映射
        Map<String, String> instIdsMap = instMapping(context);

        // 2.组装所有主套餐实例节点
        this.packageAllMainOfferInstInfo(context, instIdsMap);

        // 3.正常拼接报文后，再进行实例id的替换
        backfillInstId(context, instIdsMap);
    }

    /**
     * 组装所有主套餐商品信息
     */
    private void packageAllMainOfferInstInfo(BcmcPosContext context, Map<String, String> instIdsMap) {
        // 获取场景中所有的主套餐实例
        Map<String, KitePosOfferInstVO> mainOfferInstMap = context.getPosSceneBO().getMainOfferInstMap();
        Iterator<KitePosOfferInstVO> iterator = mainOfferInstMap.values().iterator();

        // 附加产品实例集合(附加产品作为主套餐实例封装)
        List<KitePosOfferInstVO> addRoleOfferInsts = Lists.newArrayList();

        while (iterator.hasNext()) {
            KitePosOfferInstVO offerInstVO = iterator.next();

            // 当前销售品是附加产品则添加到附加产品实例集合
            if (this.isAddRoleOfferInst(offerInstVO.getOfferInst())) {
                addRoleOfferInsts.add(offerInstVO);
                continue;
            }

            // 组装主套餐商品实例节点
            this.packageMainOfferInst(context, offerInstVO);
        }

        // 附加产品-补充通信包使用产品支持，但是补充通信包在产商品侧配置的是属性组且可以订购多次，这里需要判断多个产品实例就用属性组形式传到下游系统
        addRoleOfferInsts.forEach(addRoleOfferInstVO -> {
            // 组装附加产品信息节点
            this.packageAddRoleOfferInst(context, addRoleOfferInstVO);
        });

        // 如果goods下的付费关系没有设置，需要设置PayRelation节点
        this.supplementPayRelation(context);
    }

    /**
     * 实例映射处理
     */
    private Map<String, String> instMapping(BcmcPosContext context) {
        // 极简与联通实例id对应map
        Map<String, String> instIdMap = null;
        // 如果已存在一个以上的订单详情记录，在此进行映射处理，key是极简的实例id，value是订单中心的实例id
        if (context.getPosDto().getGoods().size() > 0) {
            instIdMap = Maps.newHashMap();
            assembleMap(context.getPosDto().getGoods(), instIdMap, context.getCustDto().getCustId(),
                context.getSceneInstId());
            // 将订单详情原有部分进行清楚再进行正常拼接，实例id已经再instIdMap映射完毕
            context.getPosDto().getGoods().clear();
        }
        return instIdMap;
    }

    /**
     * 组装主套餐商品实例节点
     */
    private void packageMainOfferInst(BcmcPosContext context, KitePosOfferInstVO offerInstVO) {
        // 组装商品信息节点
        KitePosGoodsDTO goods = this.packageGoodsInfo(context, offerInstVO);

        // 组装产品信息节点
        this.packageAllProductInfo(context, goods, offerInstVO, LocalKeyConsts.PRODUCT_TYPE_BASE);

        // 组装付费关系
        this.packagePayRelation(context, goods);

        // 资费信息通过可选包获取,只能通过主套餐往下找可选包
        this.packageGoodsFeeInfo(context, goods, offerInstVO.getOfferInst());
        context.addGoods(goods);
    }

    /**
     * 组装附加产品实例节点
     */
    private void packageAddRoleOfferInst(BcmcPosContext context, KitePosOfferInstVO addRoleOfferInstVO) {

        // 获取相同的附加产品 （TODO ： 此次逻辑没搞清楚）
        KitePosGoodsDTO goods = this.packageGoodsInfo(context, addRoleOfferInstVO);
        this.packageAllProductInfo(context, goods, addRoleOfferInstVO, LocalKeyConsts.PRODUCT_TYPE_ADD);
        context.addGoods(goods);
    }

    /**
     * 补充设置付费关系<br>
     * 商品节点中缺少付费关系的，需要获取报文中付费关系不为空作为本商品的付费关系
     */
    private void supplementPayRelation(BcmcPosContext context) {
        context.getPosDto().getGoods().forEach(kitePosGoodsDTO -> {
            if (KiteListUtils.isEmpty(kitePosGoodsDTO.getPayRelation())) {
                // 获取上下文第一个付费关系不为空商品节点
                KitePosGoodsDTO tempKitePosGoodsDTO = context.getPosDto().getGoods().stream()
                    .filter(goods -> KiteListUtils.isNotEmpty(goods.getPayRelation())).findFirst().orElse(null);

                if (Objects.nonNull(tempKitePosGoodsDTO)) {
                    // 设置付费关系
                    kitePosGoodsDTO.setPayRelation(toTrans(tempKitePosGoodsDTO.getPayRelation()));
                }
            }

        });
    }

    /**
     * 根据实例ID映射回填工单实例ID
     */
    private void backfillInstId(BcmcPosContext context, Map<String, String> instIdsMap) {
        if (MapUtils.isNotEmpty(instIdsMap)) {
            context.getPosDto().getGoods().forEach(kitePosGoodsDTO -> {
                // 商品的实例替换
                kitePosGoodsDTO.setInstanceId(instIdsMap.get(kitePosGoodsDTO.getInstanceId()));
                // parentInstId
                kitePosGoodsDTO.setParentInstId(instIdsMap.get(kitePosGoodsDTO.getParentInstId()));
                // userInstId
                if (!KiteObjectUtils.isEmpty(context.getPosDto().getUsers())) {
                    kitePosGoodsDTO.setUserInstId(context.getPosDto().getUsers().get(0).getInstanceId());
                }
                dealGoodDestItemId(context, kitePosGoodsDTO);
                // pay的实例替换
                List<KitePosGoodsPayRealtionDTO> KitePosGoodsPayRealtionDtoList = kitePosGoodsDTO.getPayRelation();
                if (KiteListUtils.isNotEmpty(KitePosGoodsPayRealtionDtoList)) {
                    for (KitePosGoodsPayRealtionDTO KitePosGoodsPayRealtionDto : KitePosGoodsPayRealtionDtoList) {
                        if (KiteStringUtils
                            .isNotEmpty(instIdsMap.get("pay" + KitePosGoodsPayRealtionDto.getAccountInstId()))) {
                            KitePosGoodsPayRealtionDto
                                .setInstanceId(instIdsMap.get("pay" + KitePosGoodsPayRealtionDto.getAccountInstId()));
                        }

                    }
                }
                // 产品的实例替换
                List<KitePosProductDTO> kitePosProductDTOList = kitePosGoodsDTO.getProducts();
                for (KitePosProductDTO kitePosProductDTO : kitePosProductDTOList) {
                    if (KiteStringUtils.isNotEmpty(instIdsMap.get(kitePosProductDTO.getInstanceId()))) {
                        kitePosProductDTO.setInstanceId(instIdsMap.get(kitePosProductDTO.getInstanceId()));
                    }
                    dealProductDestItemId(context, kitePosProductDTO);
                }
                // 资费的实例替换
                List<KitePosGoodsFeeDTO> kitePosGoodsFeeDTOList = kitePosGoodsDTO.getFees();
                if (KiteListUtils.isNotEmpty(kitePosGoodsFeeDTOList)) {
                    for (KitePosGoodsFeeDTO kitePosGoodsFeeDTO : kitePosGoodsFeeDTOList) {
                        dealGoodsFeeDestItemId(context, kitePosGoodsFeeDTO);
                    }
                }
            });
        }
    }

    private boolean isAddRoleOfferInst(KiteOfferInst offerInst) {
        String categoryId = Optional.ofNullable(OfferCache.get(offerInst.getOfferId())).map(Offer::getCateId)
            .orElse("");
        return GoodsInfoTransfer.isAddRoleOffer(offerInst.getOfferId(), categoryId);
    }

    private List<KitePosGoodsPayRealtionDTO> toTrans(List<KitePosGoodsPayRealtionDTO> payRelation) {
        List<KitePosGoodsPayRealtionDTO> result = new ArrayList<KitePosGoodsPayRealtionDTO>();
        if (!ListUtil.isEmpty(payRelation)) {
            for (KitePosGoodsPayRealtionDTO dto : payRelation) {
                KitePosGoodsPayRealtionDTO o = new KitePosGoodsPayRealtionDTO();
                String oStr = JSON.toJSONString(dto);
                o = JsonUtils.parseObject(oStr, KitePosGoodsPayRealtionDTO.class);
                result.add(o);
            }
        }
        return result;
    }

    // 组装映射map
    private void assembleMap(List<KitePosGoodsDTO> goodsList, Map<String, String> instIdMap, String custId,
        String sceneInstId) {
        List<KiteOfferInst> offerInstList = querySceneInstService.listMainOfferInsts(sceneInstId);
        List<KiteProdInst> kiteProdInstList = querySceneInstService.listProdInsts(sceneInstId);
        for (KitePosGoodsDTO posGoodsDTO : goodsList) {
            // 商品
            String kiteOfferInstId = offerInstList.stream()
                .filter(kiteOfferInst -> kiteOfferInst.getSpecId().equals(posGoodsDTO.getCode())).findAny()
                .map(KiteOfferInst::getOfferInstId).orElse("");
            if (StringUtil.isNotEmpty(kiteOfferInstId)) {
                instIdMap.put(kiteOfferInstId, posGoodsDTO.getInstanceId());

                if (KiteListUtils.isNotEmpty(posGoodsDTO.getPayRelation())) {
                    for (KitePosGoodsPayRealtionDTO kitePosGoodsPayRealtionDTO : posGoodsDTO.getPayRelation()) {
                        // 通过pay+规格code定位 PayRealtion的实例id
                        instIdMap.put("pay" + kitePosGoodsPayRealtionDTO.getAccountInstId(),
                            kitePosGoodsPayRealtionDTO.getInstanceId());
                    }
                }
            }
            // 产品
            posGoodsDTO.getProducts().forEach(posProductDTO -> {
                for (KiteProdInst kiteProdInst : kiteProdInstList) {
                    if (kiteProdInst.getSpecId().equals(posProductDTO.getCode())) {
                        instIdMap.put(kiteProdInst.getProdInstId(), posProductDTO.getInstanceId());
                    }
                }
            });

        }
    }

    /**
     * Description: <br>
     * 组装商品信息
     *
     * @author XXX<br>
     * @taskId <br>
     * @param context
     * @param goods
     * @param offerInst <br>
     */
    private KitePosGoodsDTO packageGoodsInfo(BcmcPosContext context, KitePosOfferInstVO offerInstVO) {
        KiteOfferInst offerInst = offerInstVO.getOfferInst();
        KitePosGoodsDTO goods = new KitePosGoodsDTO();
        goods.setInstanceId(offerInst.getInstId());
        goods.setCode(offerInst.getOfferId());
        goods.setCount(1);
        goods.setName(offerInst.getOfferName());
        goods.setChangeType(ChangeTypeUtils.getChangeType(offerInstVO.getActionType()));

        Offer curOffer = OfferCache.get(offerInst.getOfferId());
        // 设置商品分类编码
        if (Objects.nonNull(curOffer)) {
            goods.setCatagoryId(curOffer.getCateId());
        }

        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        InstType instType = querySceneInstService.getSceneInst(context.getSceneInstId()).getRootInstType();

        // 设置用户实例ID
        goods.setUserInstId(CuccPosServiceUtils.getUserInstId(context));

        // 设置账户
        List<KiteOfferInstAcct> offerInstAcctRels = querySceneInstService.listOfferInstAccts(context.getCustId(),
            offerInst.getOfferInstId());
        if (!KiteListUtils.isEmpty(offerInstAcctRels)) {
            offerInstAcctRels = offerInstAcctRels.stream()
                .filter((acct) -> goods.getInstanceId().equals(acct.getOfferInstId())).collect(Collectors.toList());
            if (!KiteListUtils.isEmpty(offerInstAcctRels)) {
                goods.setAccountInstId(
                    Optional.ofNullable(offerInstAcctRels.get(0)).map((acct) -> acct.getInstId()).orElse(""));
            }
        }
        // 合同
        List<KiteOfferInstContract> offerInstContractRels = querySceneInstService
            .listOfferInstContracts(context.getCustId(), offerInst.getOfferInstId());
        if (!KiteListUtils.isEmpty(offerInstContractRels)) {
            if (!KiteListUtils.isEmpty(offerInstContractRels)) {
                goods.setContractInstId(Optional.ofNullable(offerInstContractRels.get(0))
                    .map((offerInstContractRel) -> offerInstContractRel.getInstId()).orElse(""));
            }
        }
        // 设置折扣审批实例
        List<KiteOfferInstDiscount> offerInstDiscounts = querySceneInstService
            .listOfferInstDiscounts(context.getCustId(), offerInst.getOfferInstId());
        if (!KiteListUtils.isEmpty(offerInstDiscounts)) {
            // 转单强制默认挂在主商品上 add by sqy 2020.11.11
            List<KiteInstRelDTO> instRels = querySceneInstService.listInstRelsByZInst(context.getCustDto().getCustId(),
                InstType.MAIN_OFFER_INST, offerInst.getOfferInstId(), InstType.MAIN_OFFER_INST);
            if (!KiteListUtils.isEmpty(instRels)) {

            }
            else {
                goods.setDiscountInstId(Optional.ofNullable(offerInstDiscounts.get(0))
                    .map((offerInstDiscount) -> offerInstDiscount.getInstId()).orElse(""));
            }
        }
        // 收货信息实例
        List<Map<String, Object>> deliveryInfos = querySceneInstService.getExtParameterValue(context.getSceneInstId(),
            "offerInstDeliveryInfos");
        if (!KiteListUtils.isEmpty(deliveryInfos)) {
            for (Map<String, Object> delivery : deliveryInfos) {
                List<KiteAttr> kiteAttrs = (List<KiteAttr>) delivery.get("kiteAttrs");

                kiteAttrs.forEach(attr -> {
                    if (KiteStringUtils.equals("offerName", attr.getFieldName())
                        && KiteStringUtils.equals(attr.getValue(), offerInst.getOfferInstId())) {
                        goods.setDeliveryInstId(delivery.get("instId").toString());
                    }
                });
            }
        }

        if (Objects.equals(InstType.GIFT_OFFER_INST, instType)) {
            goods
                .setParentInstId(
                    Optional
                        .ofNullable(querySceneInstService
                            .getParentOfferInstByOfferInstId(context.getCustDto().getCustId(), offerInst.getInstId()))
                        .map((parent) -> parent.getOfferInstId()).orElse(""));
        }
        else {
            // 转单时成员商品实例的parentInstId取主商品实例的实例ID
            List<KiteOfferInst> mainOfferInsts = querySceneInstService.listMainOfferInsts(context.getSceneInstId());
            mainOfferInsts = mainOfferInsts.stream()
                .filter(offerInsts -> !GoodsInfoTransfer.isAddRoleOffer(offerInsts.getSpecId(), offerInsts.getAttr("cateId").getDefaultValue()))
                .collect(Collectors.toList());
            if (!KiteListUtils.isEmpty(mainOfferInsts)
                && GoodsInfoTransfer.isAddRoleOffer(offerInst.getSpecId(), offerInst.getAttr("cateId").getDefaultValue())) {
                goods.setParentInstId(mainOfferInsts.get(0).getOfferInstId());
            }
        }

        goods.setAttrs(this.packageGoodsAttrr(context, offerInstVO));

        // 添加实例ID
        this.addInstanceIdAttr(context, offerInst.getInstId(), goods, getChangeTypeByInst(offerInstVO));

        return goods;
    }

    private void dealGoodDestItemId(BcmcPosContext context, KitePosGoodsDTO goods) {
        // 补充destItemId节点
        List<KitePosGoodsDTO> kitePosGoodsDTOList = querySceneInstService.getExtParameterValue(context.getSceneInstId(),
            "oldPosGoodsDto");
        if (KiteListUtils.isNotEmpty(kitePosGoodsDTOList)) {
            String destItemId = kitePosGoodsDTOList.stream()
                .filter(kitePosGoodsDTO -> KiteStringUtils.equals(goods.getCode(), kitePosGoodsDTO.getCode())
                    && KiteStringUtils.equals(goods.getInstanceId(), kitePosGoodsDTO.getInstanceId()))
                .findFirst().map(KitePosGoodsDTO::getDestItemId).orElse("");
            if (KiteStringUtils.isNotEmpty(destItemId)) {
                goods.setDestItemId(destItemId);
            }
        }
    }

    /**
     * Description: <br>
     * 设置商品资费信息（TODO）
     */
    private void packageGoodsFeeInfo(BcmcPosContext context, KitePosGoodsDTO goods, KiteOfferInst offerInst) {
        List<KitePosGoodsFeeDTO> fees = new ArrayList<>();
        // 根据offerInst查询下一级的可选包
        List<KiteOfferInst> additionalOfferInsts = querySceneInstService
            .listAdditionalOfferInstsFromOfferInst(context.getCustDto().getCustId(), offerInst.getOfferInstId());
        additionalOfferInsts.forEach(additionalInst -> {
            // 根据实例ID获取
            KitePosOfferInstVO offerInstVO = context.getPosSceneBO().getAdditionalOfferInstMap()
                .get(additionalInst.getOfferInstId());

            if (Objects.nonNull(offerInstVO)) {
                Offer additionalOffer = OfferCache.get(additionalInst.getOfferId());
                String offerName = additionalOffer.getOfferName();

                KitePosGoodsFeeDTO fee = new KitePosGoodsFeeDTO();
                fee.setInstanceId(additionalInst.getInstId());
                fee.setCode(additionalInst.getOfferId());
                fee.setFeeName(offerName);
                fee.setAliasName(offerName);
                fee.setChangeType(ChangeTypeUtils.getChangeType(offerInst.getActionType().name()));
                fee.setType("");

                fee.setAttrs(Lists.newArrayList());
                fee.getAttrs().addAll(this.packageGoodsAttrr(context, offerInstVO));
                // 添加极简实例ID属性
                this.addInstanceIdAttr(context, additionalInst.getInstId(), fee , getChangeTypeByInst(offerInstVO));

                fees.add(fee);
            }

        });
        goods.setFees(fees);
    }

    private void dealGoodsFeeDestItemId(BcmcPosContext context, KitePosGoodsFeeDTO fee) {
        // 补充destItemId节点
        List<KitePosGoodsFeeDTO> KitePosGoodsFeeDTOList = querySceneInstService
            .getExtParameterValue(context.getSceneInstId(), "oldPosGoodsFeeDto");
        if (KiteListUtils.isNotEmpty(KitePosGoodsFeeDTOList)) {
            KitePosGoodsFeeDTO kitePosGoodsFee = KitePosGoodsFeeDTOList.stream()
                .filter(kitePosGoodsFeeDTO -> KiteStringUtils.equals(fee.getCode(), kitePosGoodsFeeDTO.getCode())
                    && (KiteStringUtils.equals(fee.getInstanceId(), kitePosGoodsFeeDTO.getKiteInstId())
                        || KiteStringUtils.equals(fee.getInstanceId(), kitePosGoodsFeeDTO.getInstanceId())))
                .findFirst().orElse(null);
            if (!KiteObjectUtils.isEmpty(kitePosGoodsFee)) {
                fee.setInstanceId(KiteStringUtils.isNotEmpty(kitePosGoodsFee.getInstanceId())
                    ? kitePosGoodsFee.getInstanceId() : fee.getInstanceId());
                fee.setDestItemId(
                    KiteStringUtils.isNotEmpty(kitePosGoodsFee.getDestItemId()) ? kitePosGoodsFee.getDestItemId() : "");
                fee.setProductDestItemId(KiteStringUtils.isNotEmpty(kitePosGoodsFee.getProductDestItemId())
                    ? kitePosGoodsFee.getProductDestItemId() : "");
                fee.setOrderDestItemId(KiteStringUtils.isNotEmpty(kitePosGoodsFee.getOrderDestItemId())
                    ? kitePosGoodsFee.getOrderDestItemId() : "");
            }
        }
    }

    private void packageAddRoleProductInfo(BcmcPosContext context, KitePosGoodsDTO goods,
        List<KitePosOfferObjInstRelVO> objInstRels) {
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        Date createDate = querySceneInstService.getSceneInst(context.getSceneInstId()).getCreateDate();
        String createDateStr = KiteDateUtils.formatDate(createDate, KiteDateUtils.DATE_TIME_FORMAT_14);

        List<KitePosProductDTO> products = new ArrayList<>();
        Map<String, KitePosProdInstVO> prodInstMap = context.getPosSceneBO().getProdInstMap();

        objInstRels.forEach((instRel) -> {
            String instId = instRel.getInstId();
            KitePosProdInstVO prodInstVO = prodInstMap.get(instId);
            if (Objects.nonNull(prodInstVO) && Objects.nonNull(prodInstVO.getProdInst())) {
                KiteProdInst prodInst = prodInstVO.getProdInst();

                KitePosProductDTO product = null;
                List<KitePosProductDTO> productList = goods.getProducts().stream()
                    .filter(pp -> KiteStringUtils.equals(pp.getCode(), prodInst.getProdId()))
                    .collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(productList)) {
                    product = productList.get(0);
                }
                if (Objects.isNull(product)) {
                    product = new KitePosProductDTO();

                    // 通过BillProdType区分是基础产品还是资费类产品，这里取基础产品
                    Product prodSpec = ProductCache.get(prodInst.getProdId());
                    String prodId = prodInst.getProdId();

                    String prodName = prodSpec.getProdName();
                    String aliasName = prodSpec.getAliasName();
                    String prodType = LocalKeyConsts.PRODUCT_TYPE_ADD;
                    product.setInstanceId(prodInst.getInstId());
                    product.setCode(prodId);
                    product.setName(prodName);
                    // product.setAliasName(aliasName);
                    product.setType(prodType);
                    product.setChangeType(ChangeTypeUtils.getChangeType(prodInst.getActionType().name())); // 新增
                }

                List<KitePosAttrDTO> kitePosAttrDTOS = product.getAttrs();
                if (KiteListUtils.isEmpty(kitePosAttrDTOS)) {
                    kitePosAttrDTOS = Lists.newArrayList();
                }
                this.packageAddRoleProdAttrInfo(context, kitePosAttrDTOS, prodInst.getAttrMap(), createDateStr,
                    prodInst.getProdInstId(), product.getType());
                product.setAttrs(kitePosAttrDTOS);
                // this.addInstanceIdAttr(context.getSceneInstId(), "instanceId", prodInst.getInstId(), product);

                products.add(product);
            }
        });

        goods.setProducts(products);
    }

    /**
     * 组装商品属性节点
     */
    private List<KitePosAttrDTO> packageGoodsAttrr(BcmcPosContext context, KitePosOfferInstVO offerInstVO) {
        List<KitePosAttrDTO> attrs = Lists.newArrayList();
        String instActionType = offerInstVO.getActionType();
        // 删除的实例不需要设置产品实例属性
        if (StringUtils.equals(instActionType, ActionType.D.name())) {
            return attrs;
        }

        Set<Entry<String, KiteAttr>> entrySet = offerInstVO.getOfferInst().getAttrMap().entrySet();
        for (Entry<String, KiteAttr> entry : entrySet) {
            KiteAttr kiteAttr = entry.getValue();
            // 如果是隐藏属性为H且没有值的 或者 订单信息属性为O的，就不放到报文中。隐藏属性只在极简端有效，例如isnull，price这些。订单属性已在order节点下了
            if (kiteAttr.getShowType().equals(LocalKeyConsts.PROD_ATTR_SHOW_TYPE_O)
                || (kiteAttr.getShowType().equals(LocalKeyConsts.KITE_ATTR_CONFIG_SHOW_TYPE_H)
                    && StringUtil.isEmpty(kiteAttr.getValue()))) {
                continue;
            }

            // 获取属性变更类型
            String changeType = CuccPosServiceUtils.getAttrChangeType(offerInstVO, kiteAttr);
            // 生成产品属性信息节点
            KitePosAttrDTO attrDTO = this.genAttrDTO(context, kiteAttr, changeType);
            if (Objects.nonNull(attrDTO)) {
                attrs.add(attrDTO);
            }
        }
        return attrs;
    }

    /**
     * 组装产品主属性信息
     */
    private List<KitePosAttrDTO> packageProdAttr(BcmcPosContext context, KitePosProdInstVO prodInstVO) {
        List<KitePosAttrDTO> attrs = Lists.newArrayList();
        String instActionType = prodInstVO.getActionType();
        // 删除的实例不需要设置产品实例属性
        if (StringUtils.equals(instActionType, ActionType.D.name())) {
            return attrs;
        }

        Set<Entry<String, KiteAttr>> entrySet = prodInstVO.getProdInst().getAttrMap().entrySet();
        for (Entry<String, KiteAttr> entry : entrySet) {
            KiteAttr attr = entry.getValue();
            // 获取属性变更类型
            String changeType = CuccPosServiceUtils.getAttrChangeType(prodInstVO, attr);
            // 生成产品属性信息节点
            KitePosAttrDTO attrDTO = this.genAttrDTO(context, attr, changeType);
            if (Objects.nonNull(attrDTO)) {
                attrs.add(attrDTO);
            }
        }
        return attrs;
    }

    /**
     * 生成产品属性节点
     */
    private KitePosAttrDTO genAttrDTO(BcmcPosContext context, KiteAttr kiteAttr, String changeType) {
        KitePosAttrDTO attr = new KitePosAttrDTO();
        attr.setCode(kiteAttr.getFieldName());
        attr.setType(LocalPosConsts.ATTR_TYPE_STRING);
        attr.setStartDate(CuccPosServiceUtils.getSceneCreateDate(context));
        attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
        attr.setValue(getAttrValue(kiteAttr));
        attr.setOriginValue(kiteAttr.getOldValue());
        attr.setCname(kiteAttr.getCname());
        attr.setChangeType(changeType);
        return attr;
    }

    /**
     * 组装产品实例节点
     */
    private KitePosProductDTO packageProductInfo(BcmcPosContext context, KitePosProdInstVO prodInstVO,
        String prodType) {
        KitePosProductDTO product = new KitePosProductDTO();

        Product prodSpec = ProductCache.get(prodInstVO.getProdInst().getProdId());

        product.setInstanceId(prodInstVO.getInstId());
        product.setCode(prodSpec.getProdId());
        product.setName(prodSpec.getProdName());
        product.setType(prodType);
        // 设置操作动作
        product.setChangeType(ChangeTypeUtils.getChangeType(prodInstVO.getActionType()));

        List<KitePosAttrDTO> kitePosAttrDTOS = Lists.newArrayList();

        // 组装产品实例属性
        kitePosAttrDTOS.addAll(this.packageProdAttr(context, prodInstVO));

        // TODO 组装主产品下功能产品属性（暂时不想通过属性组实现，先不处理）

        product.setAttrs(kitePosAttrDTOS);

        // 添加极简实例ID属性
        this.addInstanceIdAttr(context, prodInstVO.getInstId(), product, getChangeTypeByInst(prodInstVO));
        // 添加客户类型属性
        addCustTypeAttr(context, product, getChangeTypeByInst(prodInstVO));


        return product;
    }

    /**
     * Description: <br>
     * 组装套餐下产品节点信息
     *
     * @author XXZ<br>
     * @taskId <br>
     * @param context
     * @param goods
     * @param offerInstVO
     * @param offerInstVO <br>
     */
    private void packageAllProductInfo(BcmcPosContext context, KitePosGoodsDTO good, KitePosOfferInstVO offerInstVO,
        String prodType) {
        // 产品信息节点集合
        List<KitePosProductDTO> products = new ArrayList<>();

        // 套餐销售品包含产品
        List<KitePosOfferObjInstRelVO> objInstRels = offerInstVO.getOfferObjInstRels();
        for (KitePosOfferObjInstRelVO instRel : objInstRels) {
            KitePosProdInstVO prodInstVO = CuccPosServiceUtils.getProdInstVOByInstId(context, instRel.getInstId());

            if (Objects.isNull(prodInstVO) || Objects.isNull(prodInstVO.getProdInst())) {
                continue;
            }
            KiteProdInst prodInst = prodInstVO.getProdInst();
            // 资费产品不处理
            if (CuccPosServiceUtils.checkBillProdType(prodInst.getProdId())) {
                continue;
            }

            // 添加产品信息节点
            products.add(packageProductInfo(context, prodInstVO, prodType));

        }

        // 设置所有产品信息节点
        good.setProducts(products);
    }

    private void dealProductDestItemId(BcmcPosContext context, KitePosProductDTO product) {
        // 补充destItemId节点
        List<KitePosProductDTO> kitePosProductDTOList = querySceneInstService
            .getExtParameterValue(context.getSceneInstId(), "oldPosProdDto");
        if (KiteListUtils.isNotEmpty(kitePosProductDTOList)) {
            String prodId = querySceneInstService.getExtParameterValue(context.getSceneInstId(), "OLD_PROD_ID");
            String destItemId = "";
            if (!KiteStringUtils.isEmpty(prodId)) {
                String prodIda = prodId;
                destItemId = kitePosProductDTOList.stream()
                    .filter(kitePosProductDTO -> KiteStringUtils.equals(prodIda, kitePosProductDTO.getCode())
                        && KiteStringUtils.equals(product.getInstanceId(), kitePosProductDTO.getInstanceId()))
                    .findFirst().map(KitePosProductDTO::getDestItemId).orElse("");
            }
            if (!KiteStringUtils.isNotEmpty(destItemId)) {
                destItemId = kitePosProductDTOList.stream()
                    .filter(kitePosProductDTO -> KiteStringUtils.equals(product.getCode(), kitePosProductDTO.getCode())
                        && KiteStringUtils.equals(product.getInstanceId(), kitePosProductDTO.getInstanceId()))
                    .findFirst().map(KitePosProductDTO::getDestItemId).orElse("");
            }
            if (KiteStringUtils.isNotEmpty(destItemId)) {
                product.setDestItemId(destItemId);
            }
        }
    }

    private KitePosAttrDTO genKitePosAttr(KiteAttr kiteAttr, String createDateStr, boolean isBcmcFlow) {
        KitePosAttrDTO attr = new KitePosAttrDTO();
        attr.setCode(kiteAttr.getFieldName());
        attr.setType("STRING");
        attr.setStartDate(createDateStr);
        attr.setEndDate(LocalKeyConsts.ATTR_SEND_DATE);
        attr.setValue(getAttrValue(kiteAttr));
        attr.setOriginValue(kiteAttr.getOldValue());
        if (isBcmcFlow) {
            attr.setCname(kiteAttr.getCname());
        }
        // 资费信息属性部分有默认值，修改属性后需要用修改后的属性
        if (KiteStringUtils.isNotEmpty(kiteAttr.getValue())
            && InstType.ADDITIONAL_OFFER_INST.equals(kiteAttr.getInstType())) {
            attr.setValue(Optional.ofNullable(kiteAttr.getValue()).orElse(""));
        }
        // 设置生失效时间 -- 资费信息不需要设置
        if ("200000172".equals(kiteAttr.getFieldName())
            && !InstType.ADDITIONAL_OFFER_INST.equals(kiteAttr.getInstType())) {
            attr.setValue(DateUtils.formatDate(DateUtils.getStartOfDay(), DateUtils.DEFAULT_PATTERN));
        }
        if ("200000173".equals(kiteAttr.getFieldName())
            && !InstType.ADDITIONAL_OFFER_INST.equals(kiteAttr.getInstType())) {
            attr.setValue(DateUtils.formatDate(DateUtils.getEndOfDay(), DateUtils.DEFAULT_PATTERN));
        }
        // PCRF附件取第一个的URL
        if ("200004167".equals(kiteAttr.getFieldName()) && !KiteStringUtils.isEmpty(kiteAttr.getValue())) {
            JSONArray arrs = JSONArray.parseArray(kiteAttr.getValue());
            JSONObject obj = (JSONObject) arrs.get(0);
            String url = (String) obj.get("attachmentUrl");
            attr.setValue(url);
        }
        return attr;
    }

    /**
     * 未了实现展示方式而加的属性分组，此分组并不在产商品侧配置，无需按属性转传到下游系统
     *
     * @param groupId
     * @return
     */
    private boolean isFakeGroup(String groupId) {
        return !KiteObjectUtils.isEmpty(DcPublicCache.get("20201207002", groupId));
    }

    private List<KiteAttr> attrMapToList(Map<String, KiteAttr> prodAttrMap) {
        List<KiteAttr> prodAttrs = Lists.newArrayList();
        Iterator<String> ii = prodAttrMap.keySet().iterator();
        while (ii.hasNext()) {
            String key = ii.next();
            if (isFakeGroup(prodAttrMap.get(key).getGroupId())) {
                prodAttrMap.get(key).setGroupId("");
                prodAttrMap.get(key).setGroupName("");
            }
            prodAttrs.add(prodAttrMap.get(key));
            // 移除属性组属性
            if (!KiteStringUtils.isEmpty(prodAttrMap.get(key).getGroupId())) {
                ii.remove();
            }
        }
        return prodAttrs;
    }

    private void packageAttrGroups(BcmcPosContext context, List<KitePosAttrDTO> kitePosAttrDTOS,
        Map<String, KiteAttr> prodAttrMap, String createDateStr, String prodInstId, String prodType) {
        List<KiteAttr> prodAttrs = this.attrMapToList(prodAttrMap);
        List<KiteAttr> prodGrpAttrs = prodAttrs.stream().filter(attr -> !KiteStringUtils.isEmpty(attr.getGroupId()))
            .collect(Collectors.toList());
        Map<String, List<KiteAttr>> grpListAttr = KiteListUtils.groupBy(prodGrpAttrs, "groupId");

        if (!KiteListUtils.isEmpty(prodGrpAttrs)) {
            Map<String, Object> grpMap = new HashMap<String, Object>();
            KitePosAttrDTO grpAttr = new KitePosAttrDTO();
            Iterator<String> it = grpListAttr.keySet().iterator();
            while (it.hasNext()) {
                String key = it.next();
                if ("null".equals(key)) {
                    continue;
                }
                KitePosAttrDTO grpattr = null;
                // 取相同code的属性组
                List<KitePosAttrDTO> grpAttrs = kitePosAttrDTOS.stream()
                    .filter(attr -> KiteStringUtils.equals(key, attr.getCode())).collect(Collectors.toList());
                if (!KiteListUtils.isEmpty(grpAttrs)) {
                    grpattr = grpAttrs.get(0);
                }
                if (Objects.nonNull(grpattr)) {
                    grpAttr = grpattr;
                    grpMap = JSONObject.parseObject(grpattr.getValue(), Map.class);
                    // 移走已添加的属性组，待添加属性组实例后再设置
                    kitePosAttrDTOS.removeIf(attr -> KiteStringUtils.equals(key, attr.getCode()));
                }
                grpAttr.setCode(key);
                grpAttr.setType("ATTR_GROUP");

                List<KiteAttr> grpAttrList = (List<KiteAttr>) grpListAttr.get(key);

                List<KitePosAttrDTO> attrs = new ArrayList<>();
                for (KiteAttr kiteAttr : grpAttrList) {
                    if (KiteStringUtils.isEmpty(kiteAttr.getValue())) {
                        continue;
                    }
                    attrs.add(genKitePosAttr(kiteAttr, createDateStr, context.getIsBcmcFlow()));

                    // 已经在属性组中传递，将属性移除
                    prodAttrMap.remove(kiteAttr.getFieldName());
                }
                grpMap.put(prodInstId, attrs);
            }
            grpAttr.setValue(JSONObject.toJSONString(grpMap));
            kitePosAttrDTOS.add(grpAttr);
        }
    }

    private void packageAddRoleProdAttrInfo(BcmcPosContext context, List<KitePosAttrDTO> kitePosAttrDTOS,
        Map<String, KiteAttr> prodAttrMap, String createDateStr, String prodInstId, String prodType) {
        this.packageAttrGroups(context, kitePosAttrDTOS, prodAttrMap, createDateStr, prodInstId, prodType);
        List<KiteAttr> prodAttrs = this.attrMapToList(prodAttrMap);
        // 非分组属性
        prodAttrs.forEach(kiteAttr -> {
            // 排除已存在的属性
            if (!KiteStringUtils.isEmpty(kiteAttr.getValue()) && !kitePosAttrDTOS.stream()
                .anyMatch(attr -> KiteStringUtils.equals(attr.getCode(), kiteAttr.getFieldName()))) {
                kitePosAttrDTOS.add(genKitePosAttr(kiteAttr, createDateStr, context.getIsBcmcFlow()));
            }
        });
    }

    /**
     * 组装主产品下功能产品属性值<br>
     * 产品下功能产品的属性，物联网的APN，资费计划，通信计划使用功能产品实例实现支撑<br>
     */
    private List<KitePosAttrDTO> packageProdFuncAttrs(BcmcPosContext context, KitePosProdInstVO prodInstVO) {
        List<KitePosAttrDTO> prodFuncAttrs = Lists.newArrayList();

        return prodFuncAttrs;
    }

    private void packagePayRelation(BcmcPosContext context, KitePosGoodsDTO goods) {
        List<KitePosGoodsPayRealtionDTO> payRelations = new ArrayList<>();
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);

        String createDateStr = CuccPosServiceUtils.getSceneCreateDate(context);
        // 传输计划变更时，payRelation有数据不需要重新封装
        if (!KiteListUtils.isEmpty(goods.getPayRelation())) {
            return;
        }
        List<KiteOfferInstAcct> offerInstAcctRels = querySceneInstService.listOfferInstAccts(context.getCustId(),
            goods.getInstanceId());
        if (Objects.isNull(offerInstAcctRels)) {
            offerInstAcctRels = new ArrayList<>();
        }

        offerInstAcctRels.forEach((acctRel) -> {
            KitePosGoodsPayRealtionDTO payRelation = new KitePosGoodsPayRealtionDTO();

            String instanceId = IdUtils.generateInstId(InstType.PROD_INST_ACCT);
            payRelation.setInstanceId(instanceId);
            payRelation.setStartDate(KiteStringUtils.isEmpty(acctRel.getStartDate()) ? createDateStr
                : KiteDateUtils.getCurrentDayOfMonth(acctRel.getStartDate().split("-")[0],
                    acctRel.getStartDate().split("-")[1]));
            payRelation.setEndDate(KiteStringUtils.isEmpty(acctRel.getEndDate()) ? LocalKeyConsts.ATTR_SEND_DATE
                : KiteDateUtils.getLastDayOfMonth(acctRel.getEndDate().split("-")[0],
                    acctRel.getEndDate().split("-")[1]));
            payRelation.setPayWay(acctRel.getPayWay()); // 0全额
            payRelation.setPayLimit(acctRel.getPayLimit()); //
            payRelation.setPayitemCode(acctRel.getAcctItemId()); // 0全额
            payRelation.setIsDefault(Integer.valueOf(Optional.ofNullable(acctRel.getIsDefault()).orElse("0"))); // 默认
            payRelation.setAccountCycle(acctRel.getAccountCycle());
            payRelation.setFeeCycle(acctRel.getFeeCycle());
            payRelation.setAccountInstId(getAccountInstId(context, acctRel.getAcctId()));
            payRelation.setFeeCycle(acctRel.getPayCycle());
            payRelation.setAccountCycle(acctRel.getAccountCycle());
            payRelation.setChangeType(ChangeTypeUtils.getChangeType(acctRel.getActionType().name()));

            String sceneInstId = context.getSceneInstId();
            List<InstAttrDTO> attrConfigs = queryScenePersonService
                .listKiteConfigAttrs(sceneInstId, LocalKeyConsts.TRANSFER_DISPLAY_OBJECT_TYPE).getResultObject()
                .stream()
                .filter(instAttrDTO -> LocalKeyConsts.KITE_ATTR_CONFIG_SHOW_TYPE_D.equals(instAttrDTO.getShowType()))
                .collect(Collectors.toList());
            // 过户时，选择默认付费关系时，设置changetype
            if (KiteListUtils.isNotEmpty(attrConfigs)) {
                Map<String, String> orderAttrMap = new HashMap<String, String>();
                attrConfigs.forEach(orderAttr -> orderAttrMap.put(orderAttr.getFieldName(), orderAttr.getValue()));

                String isDefault = orderAttrMap.get("is_trans_acct");
                if (KiteStringUtils.isEqual(isDefault, "1")) {
                    payRelation.setChangeType("9");
                }
            }

            payRelations.add(payRelation);
        });

        goods.setPayRelation(payRelations);
    }

    private String getAccountInstId(BcmcPosContext context, String acctId) {
        if (KiteListUtils.isEmpty(context.getPosDto().getAccounts())) {
            return "";
        }
        List<KitePosAccountDTO> accounts = context.getPosDto().getAccounts().stream()
            .filter((acct) -> acctId.equals(acct.getAccountId())).collect(Collectors.toList());
        return accounts.get(0).getInstanceId();
    }

    private String getAttrValue(KiteAttr kiteAttr) {
        return KiteStringUtils.isEmpty(kiteAttr.getValue())
            ? (KiteStringUtils.isEmpty(kiteAttr.getDefaultValue()) ? "" : kiteAttr.getDefaultValue())
            : kiteAttr.getValue();
    }

}
